#include "utils/os_utils.hpp"
#include <cstdlib>
#include "fmt/core.h"
#include "utils/log.hpp"
#include "utils/path_utils.hpp"
#include "app/app_base.hpp"

#if _WIN32

#include <Windows.h>
#include <shellapi.h>
#include <cmath>
#include <utils/win32_utility.hpp>

#pragma comment(lib,"Shell32.lib")

void Delay(double seconds)
{
    //HANDLE timer;
    //LARGE_INTEGER ft;
    //ft.QuadPart = seconds * 10000000;
    //ft.QuadPart = std::max<LONGLONG>(10, ft.QuadPart);
    //ft.QuadPart *= -1;

    //timer = CreateWaitableTimer(NULL, TRUE, NULL);
    //SetWaitableTimer(timer, &ft, 0, NULL, NULL, FALSE);
    //WaitForSingleObject(timer, INFINITE);
    //CloseHandle(timer);
    Sleep(DWORD(seconds * 1000));
}

void DefaultAppOpen(const std::string &path)
{
    // 简单实现，使用 start
    //std::string cmd = fmt::format("start \"{}\"", path);
    //L_DEBUG("Execute Command: %s", cmd.c_str());
    //system(cmd.c_str()); 
    std::wstring wpath = fromUtf8(path);
    ShellExecuteW(NULL, L"open", wpath.c_str(), NULL, NULL, SW_SHOWDEFAULT);
}

void RestartApp()
{
    auto exe_path = GetAppExecutablePath();
    auto wpath = fromUtf8(exe_path.data());

    STARTUPINFOW si{ sizeof(si) };
    PROCESS_INFORMATION pi{};

    std::wstring args;
    if (wpath.find(L' ') != std::wstring::npos)
    {
        args = L"\"" + wpath + L"\"";
    }
    else
    {
        args = wpath;
    }
    args.push_back(L' ');
    args.append(L"--wait");
    args.push_back(0);

    DWORD dwResult = CreateProcessW(
        wpath.c_str(),
        &args[0],
        nullptr,
        nullptr,
        FALSE,
        CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
        nullptr,
        nullptr,
        &si,
        &pi
    );

    if (dwResult) // start success
        App->Exit();

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

#elif __unix__
#include <time.h>
#include <unistd.h>
void Delay(double seconds)
{
    constexpr long long NS_PER_SEC = 1000000000;

    timespec tv{};
    tv.tv_sec = (time_t)seconds;
    tv.tv_nsec = ((decltype(tv.tv_nsec))(seconds * NS_PER_SEC)) % NS_PER_SEC;
    nanosleep(&tv, nullptr);
}

void DefaultAppOpen(const std::string &path)
{
    // 简单实现，使用 xdg-open
    std::string cmd = fmt::format("xdg-open \"{}\"", path);
    L_DEBUG("Execute Command: %s", cmd.c_str());
    system(cmd.c_str()); 
}

void RestartApp()
{
    auto exe_path = GetAppExecutablePath();
    auto pid = fork();
    if (pid < 0) {
        perror("fork");
    } else if (pid > 0) {
        App->Exit(); // parent, exit
    } else {
        static char additional[] = "--wait";
        std::vector<char*> args { (char*)exe_path.data(), additional, nullptr };
        execv(exe_path.data(), args.data());
        exit(1);
    }
}

#else
#error "Code Not Ported!"
#endif
